package com.handpay.framework.utils;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.net.Uri;
import android.text.TextUtils;

import com.handpay.zztong.hp.config.ZZTConstant;
import com.handpay.zztong.hp.log.HPLog;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 线程和handler用的太随意，需要修改。暂时就这样
 * 
 * @author jmshuai
 * 
 */
public class BitmapLoader {
	final private static String TAG = BitmapLoader.class.getName();
	// 用于加载系统资源的图片
	private Context mContext;
	private static BitmapLoader mInstance;

	public static synchronized BitmapLoader getInstance(Context context) {
		if (null == mInstance) {
			mInstance = new BitmapLoader(context.getApplicationContext());
		}
		return mInstance;
	}

	private BitmapLoader(Context c) {
		mContext = c;
	}

	public static class LoadJob<Result> {
		private String mKey;
		private String mUri;
		private ImageCallback mImageCallback;
		private Result mResult;

		public String getKey() {
			return mKey;
		}

		public void setKey(String mKey) {
			this.mKey = mKey;
		}

		public String getUri() {
			return mUri;
		}

		public void setUri(String mUri) {
			this.mUri = mUri;
		}

		public ImageCallback getImageCallback() {
			return mImageCallback;
		}

		public void setImageCallback(ImageCallback mImageCallback) {
			this.mImageCallback = mImageCallback;
		}

		public LoadJob(String key, String uri, ImageCallback callback) {
			mKey = key;
			mUri = uri;
			mImageCallback = callback;
		}

		public Result getResult() {
			return mResult;
		}

		public void setResult(Result mResult) {
			this.mResult = mResult;
		}
	}

	private static Bitmap loadImageFromUri(String uri) {

		InputStream i = null;
		try {
			ContentResolver cr = mInstance.mContext.getContentResolver();
			i = cr.openInputStream(Uri.parse(uri));
			final BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			Rect outPadding = new Rect();
			BitmapFactory.decodeStream(i, outPadding, options);
			// Calculate inSampleSize
			options.inSampleSize = calculateInSampleSize(options,
					ZZTConstant.MAX_PX_LENGTH, ZZTConstant.MAX_PX_LENGTH);
			// Decode bitmap with inSampleSize set
			options.inJustDecodeBounds = false;
			i.close();
			HPLog.i("loadImageFromUri", options.inSampleSize);
			i = cr.openInputStream(Uri.parse(uri));
			return BitmapFactory.decodeStream(i, outPadding, options);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != i) {
					i.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public void asynLoadBitmap(String userName, String imageUrl,
			ImageCallback imageCallback) {
		asynLoadBitmap(userName, imageUrl, imageCallback, true);
	}

	@SuppressWarnings("unchecked")
	public void asynLoadBitmap(String userName, String imageUrl,
			ImageCallback imageCallback, final boolean isCache) {
		final BitmapCacheUtils bcu = BitmapCacheUtils.getInstance();

		if (isCache && bcu.isInCache(userName)) {
			// 从缓存中获取
			// yanglun bcu get
			Bitmap drawable = bcu.getBitmap(userName);
			if (drawable != null) {
				imageCallback.imageLoaded(drawable, imageUrl);
				return;
			}

		}

		LoadJob<Bitmap> lj = new LoadJob<Bitmap>(userName, imageUrl,
				imageCallback);
		new MyAsyncTask<LoadJob<Bitmap>, Void, LoadJob<Bitmap>>() {
			@Override
			protected void onPostExecute(LoadJob<Bitmap> result) {
				if (null != result.getResult()) {
					// yanglun bcu put
					bcu.putInCache(result.getKey(), result.getResult());
				}
				result.getImageCallback().imageLoaded(result.getResult(),
						result.getUri());
				super.onPostExecute(result);
			}

			@Override
			protected LoadJob<Bitmap> doInBackground(LoadJob<Bitmap>... params) {
				String uri = params[0].getUri();
				Bitmap bitmap;
				if (uri.startsWith("content") && isCache) {
					bitmap = loadImageFromUri(uri);
				} else {
					bitmap = loadImageFromUrl(uri, isCache);
				}
				params[0].setResult(bitmap);
				return params[0];
			}
		}.execute(lj);
		return;
	}

	public static boolean isHttpUrl(String imageUrl) {
		return imageUrl.startsWith("http://");
	}

	/**
	 * 这是个耗时操作。如果需要异步回调，请调用asynLoadBitmap这个方法。
	 * 
	 * @param userName
	 * @param imageUrl
	 * @return
	 */
	public Bitmap loadBitmap(String userName, String imageUrl) {
		final BitmapCacheUtils bcu = BitmapCacheUtils.getInstance();
		if (bcu.isInCache(userName)) {
			// 从缓存中获取
			Bitmap drawable = bcu.getBitmap(userName);
			if (null != drawable) {
				return drawable;
			}
		}
		Bitmap bitmap;
		if (imageUrl.startsWith("content")) {
			bitmap = loadImageFromUri(imageUrl);
		} else {
			bitmap = loadImageFromUrl(imageUrl);
		}
		if (null != bitmap) {
			bcu.putInCache(userName, bitmap);
		}
		return bitmap;
	}

	public static byte[] readBytes3(InputStream in) throws IOException {
		BufferedInputStream bufin = new BufferedInputStream(in);
		int buffSize = 1024;
		ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize);

		// System.out.println("Available bytes:" + in.available());

		byte[] temp = new byte[buffSize];
		int size = 0;
		while ((size = bufin.read(temp)) != -1) {
			out.write(temp, 0, size);
		}
		bufin.close();

		byte[] content = out.toByteArray();
		return content;
	}

	public byte[] loadBitmapNoCompress(String uri) {
		URL m;
		InputStream i;
		try {
			m = new URL(uri);
			i = (InputStream) m.getContent();
		} catch (MalformedURLException me) {
			HPLog.e("CommonUtils", "loadImageFromUrl", me);
			return null;
		} catch (IOException ioe) {
			HPLog.e("CommonUtils", "loadImageFromUrl", ioe);
			return null;
		}
		try {

			return readBytes3(i);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != i) {
					i.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public static int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {

			final int halfHeight = height;
			final int halfWidth = width;

			// Calculate the largest inSampleSize value that is a power of 2 and
			// keeps both
			// height and width larger than the requested height and width.
			while ((halfHeight / inSampleSize) > reqHeight
					|| (halfWidth / inSampleSize) > reqWidth) {
				inSampleSize *= 2;
			}
		}

		return inSampleSize;
	}

	/**
	 * 从缓存从网络拿下来的图片。下次访问网络直接拿本地的
	 * 
	 * @param uri
	 * @return 替换地址。
	 */
	// map什么时候清除？
	private static Map<String, String> map = new ConcurrentHashMap<String, String>();

	private static String getUri(String uri) {
		if (TextUtils.isEmpty(uri)) {
			return null;
		}
		return map.get(uri);
	}

	/**
	 * 
	 * @param uri
	 *            访问网络的uri。
	 * @return 如果成功保存到本地，返回本地的位置；访问不了uri，返回为null; 其他情况返回uri本身
	 */
	private static String trySaveFile(String uri) {
		URL m;
		InputStream i;
		try {
			m = new URL(uri);
			i = (InputStream) m.getContent();
		} catch (MalformedURLException me) {
			HPLog.e("CommonUtils", "loadImageFromUrl", me);
			return null;
		} catch (IOException ioe) {
			HPLog.e("CommonUtils", "loadImageFromUrl", ioe);
			return null;
		}
		int startIndex = uri.lastIndexOf("/");
		String strFileName = uri.substring(startIndex);
		// File f = CommonUtils.randomFile(CommonUtils.getAccessDir());
		File f = CommonUtils.getAutoExistFile(CommonUtils.getAccessDir(),
				strFileName);

		// FIXME 如果如果从网络没有读取到任何数据呢？或404呢？也会存的吧！
		try {

			if (f.createNewFile()) {
				BufferedOutputStream bos = null;
				try {
					bos = new BufferedOutputStream(new FileOutputStream(f));
					byte[] array = new byte[1024];
					int length;
					while (0 < (length = i.read(array, 0, 1024))) {
						bos.write(array, 0, length);
						Arrays.fill(array, (byte) 0);
					}
					// 成功保存在本地之后，做映射。

					Uri u = Uri.fromFile(f);

					map.put(uri, u.toString());
					uri = u.toString();
				} catch (IOException ioe) {
					HPLog.e("CommonUtils", "loadImageFromUrl", ioe);
					// 如果出现异常。删除掉这个文件。
					f.delete();
				} finally {
					if (null != bos) {
						bos.close();
					}
					if (null != i) {
						i.close();
					}
				}
			}
		} catch (IOException ioe) {
			HPLog.e("CommonUtils", "loadImageFromUrl", ioe);
		}
		return uri;
	}

	private static Bitmap loadImageFromUrl(String uri) {
		return loadImageFromUrl(uri, true);
	}

	private static Bitmap loadImageFromUrl(String uri, boolean isCache) {

		URL m;
		InputStream i = null;
		// yanglun2 get map
		String u = getUri(uri);

		// 如果找到了，替换
		if (!TextUtils.isEmpty(u)) {
			// 修复重复下载的bug。TODO: cache应该放在数据库，或存在硬盘，否则重新启动应用，还是会重复下载
			File file = new File(URI.create(u));
			if (!isCache || !file.exists()) {
				map.remove(uri);
			} else {
				uri = u;
			}
		}
		try {
			// 如果是网络请求，先保存到本地。
			if (uri.startsWith("http")) {
				u = trySaveFile(uri);
				if (!TextUtils.isEmpty(u)) {
					uri = u;
				} else {
					// 如果访问不了，返回Bitmap为空
					return null;
				}
			}
			// 剩下的应该就是访问本地文件了。
			HPLog.i("loadImageFromUrl", "pre2 uri:" + uri);
			m = new URL(uri);
			i = (InputStream) m.getContent();
			final BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			Rect outPadding = new Rect();
			HPLog.i("time", "before get option:" + uri);
			BitmapFactory.decodeStream(i, outPadding, options);
			HPLog.i("time", "after get option:" + uri);
			// Calculate inSampleSize
			options.inSampleSize = calculateInSampleSize(options,
					ZZTConstant.MAX_PX_LENGTH, ZZTConstant.MAX_PX_LENGTH);
			// Decode bitmap with inSampleSize set
			options.inJustDecodeBounds = false;
			i.close();
			i = (InputStream) m.getContent();
			HPLog.i("loadImageFromUri", options.inSampleSize);
			HPLog.i("time", "before decode" + uri);
			Bitmap b = BitmapFactory.decodeStream(i, outPadding, options);
			HPLog.i("time", "after decode" + uri);
			return b;
		} catch (MalformedURLException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != i) {
					i.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	// 回调接口
	public interface ImageCallback {
		void imageLoaded(Bitmap bitmap, String imageUrl);
	}
}
